package one.bugu.zookeeper.rpc.framework.zookeeper;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: LangK
 * Created Date 2019/2/11
 * Time: 16:35
 * Description: zookeeper工具
 */
public class ZooKeeperHelper {

    private static Logger logger = LoggerFactory.getLogger(ZooKeeperHelper.class);

    /**
     * 超时时间
     */
    private static final int SESSION_TIME_OUT = 10000;

//    private static CountDownLatch countDownLatch;

    private ZooKeeper zookeeper;

    private Watcher watcher;
    private String url;

    public ZooKeeperHelper(String url, Watcher watcher) {
        this.url = url;
        this.watcher = watcher;
    }

    private ZooKeeper getZooKeeper(String url) {
        if (zookeeper == null) {
            synchronized (ZooKeeperHelper.class) {
                if (zookeeper == null) {
//                    countDownLatch = new CountDownLatch(1);
                    try {
                        zookeeper = buildClient(url);//如果失败，下次还有成功的机会
//                        if (zookeeper != null) {
//                            countDownLatch.await(SESSION_TIME_OUT, TimeUnit.MILLISECONDS);
//                        }
                    } catch (Exception e) {
                        logger.error("构建ZOOKEEPER异常", e);
                    } finally {
//                        countDownLatch = null;
                    }
                }
            }
        }
        return zookeeper;
    }

    private ZooKeeper buildClient(String url) {
        try {
            zookeeper = connectZookeeper(url);
            if (zookeeper == null) {
                return null;
            }
            return zookeeper;
        } catch (Exception e) {
            throw new RuntimeException("init zookeeper fail.", e);
        }
    }


    /**
     * 创建根节点
     *
     * @param url
     */
    private ZooKeeper connectZookeeper(String url) {
        try {
            if (watcher==null){
                watcher = new SessionWatcher();
            }
            ZooKeeper zooKeeper = new ZooKeeper(url, SESSION_TIME_OUT, watcher);
            return zooKeeper;
        } catch (Exception e) {
            logger.error("ZOOKEEPER连接异常", e);
        }
        return null;
    }

    /**
     * 创建节点
     *
     * @param path
     * @param data
     */
    public String createNode(String path, String data) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (data == null) {
            data = "";
        }
        if (zookeeper != null) {
            try {
                return zookeeper.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            } catch (Exception e) {
                logger.error("创建节点异常", e);
            }
            return null;
        } else {
            return null;
        }
    }

    /**
     * 创建临时节点
     *
     * @param path
     * @param data
     */
    public String createTempNode(String path, String data) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (data == null) {
            data = "";
        }
        if (zookeeper != null) {
            try {
                return zookeeper.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
            } catch (Exception e) {
                logger.error("创建节点异常", e);
            }
            return null;
        } else {
            return null;
        }
    }

    /**
     * 是否存在节点
     *
     * @param path
     */
    public boolean existsNode(String path) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            try {
                Stat stat = zookeeper.exists(path, watcher);
                if (stat != null) {
                    return true;
                }
            } catch (Exception e) {
                logger.error("判断节点是否存在异常", e);
            }
        }
        return false;
    }


    /**
     * 获取路径下所有子节点
     *
     * @param path
     * @return
     */
    public List<String> getChildren(String path) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            try {
                List<String> children = zookeeper.getChildren(path, watcher);
                return children;
            } catch (Exception e) {
                logger.error("获取子节点异常", e);
            }
        }
        return null;
    }

    /**
     * 获取节点上面的数据
     *
     * @param path  路径
     * @return
     */
    public String getData(String path) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            byte[] data = new byte[0];
            try {
                data = zookeeper.getData(path, watcher, null);
            } catch (Exception e) {
                logger.error("获取节点下的数据异常", e);
            }
            if (data == null) {
                return "";
            }
            return new String(data);
        }
        return "";
    }

    /**
     * 设置节点信息
     *
     * @param path  路径
     * @param data  数据
     * @return    
     */
    public Stat setData(String path, String data) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            try {
                Stat stat = zookeeper.setData(path, data.getBytes(), -1);
                return stat;
            } catch (Exception e) {
                logger.error("设置节点数据异常", e);
            }
        }
        return null;
    }

    /**
     * 删除节点
     *
     * @param path
     */
    public void deleteNode(String path) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            try {
                zookeeper.delete(path, -1);
            } catch (Exception e) {
                logger.error("删除节点数据异常", e);
            }
        }
    }

    /**
     * 获取创建时间
     *
     * @param path
     * @return
     */
    public String getCTime(String path) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            Stat stat = null;
            try {
                stat = zookeeper.exists(path, watcher);
                return String.valueOf(stat.getCtime());
            } catch (Exception e) {
                logger.error("获取创建时间异常", e);
            }
        }
        return "";
    }

    /**
     * 获取某个路径下孩子的数量
     *
     * @param path
     * @return
     * @throws KeeperException    * @throws InterruptedException
     */
    public Integer getChildrenNum(String path) {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            int childenNum = 0;
            try {
                childenNum = zookeeper.getChildren(path, watcher).size();
            } catch (Exception e) {
                logger.error("获取某个路径下孩子的数量异常", e);
            }
            return childenNum;
        }
        return 0;
    }

    /**
     * 关闭连接
     *
     */
    public void closeConnection() {
        if (zookeeper == null) {
            getZooKeeper(url);
        }
        if (zookeeper != null) {
            try {
                zookeeper.close();
            } catch (InterruptedException e) {
                logger.error("关闭连接异常", e);
            }
        }
        zookeeper = null;
    }


    class SessionWatcher implements Watcher {

        public void process(WatchedEvent event) {
            if (event.getState() == Watcher.Event.KeeperState.SyncConnected) {
                logger.info("Watch received SyncConnected event");
            } else if (event.getState() == Event.KeeperState.Expired) {
                logger.info("Watch received Session Expired event");
            } else if (event.getState() == Event.KeeperState.Disconnected) {
                logger.info("Watch received Disconnected event");
            }
        }
    }


}
